/***************************************************************
                      cb_build.c
***************************************************************
Zscore_grand2 - called after a row in the sparse matrix is created
init_Zclone - called when a Zset is recomputed, it clears fields
              in the clones matrix entry that were used during computation
init_Zset -   called when a Zset is recomputed
get_Zset  -   called when there are multiple CBmaps. This is incremented
              during Build_Contigs, which is not necessary as each CBmap
              is instantiated (OKed) once it is created. It is necessary for
              Calc and Selected, as they are displayed.

Zbuild_matrix - build the initial matrix. Zcreate_node fills in the rows.
Zcreate_nodes - for serial and Fp/Gel/Add shared.
Zmark_possible_buried - computes buried clones - not used by Fp/Gel/Add

Zfree_cb_data_structures - 
little_wrap_up -
big_wrap_up -

ZZ.matrix.set: -2 ignore, -1 no set, else >=0 for set number
ZZ.matrix.high_match:  -1 no parent, >=0 parent index into matrix
***************************************************************/
#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <semaphore.h>
#include <sys/times.h>

#define ZZTOP
#include "clam.h"

extern int init_CpM(), get_Zset(), scanClamA(), scanClam2();
extern int showClam(), showClam2();
extern void quitCB(), drawCBmap();

extern int Zrule_grand,    cnt_nodes;
extern void quitCB(), cleanCB(),  clearMsg();
extern void unbury(), Start_timer(), Zmark_possible_buried(), OK_Zset();
extern void init_Zset(), End_timer(), Zproj_results(), ZbuildCpM(), settime();
extern int  ZscoreCpM();
extern double total_cmp;
extern sem_t cmp_mutex;

extern int *local_cnt_cmp;
extern int *local_cnt_olap;
extern int *local_cnt_nodes;

void Zsulston(struct tmpCz* clone1, struct tmpCz* clone2, struct tmpSz* result);
int ZscoreCpM(struct tmpCz* clone1, struct tmpCz* clone2, struct tmpSz* result);
ZNODE  *Znew_node_serial(), *Znew_node_shared();
static void compute_f_plus_f_minus (int exponent, CLONE *clonei, CLONE *clonej,int,int);
static int coord_intersect(int x1,int x2,int w1,int w2);
static void compute_coords(int *lc,int *rc,  CLONE *clone);
static void clear_old_remarks(CLONE *clone);
extern void  append_remark(int, char *);

int  cnt_overlap, cnt_nodes, cnt_cmp;
double total_cmp;
int cmp_cnt = 0;

#define BUFSZ 120

/***************************************************************/
const char* timer_str(float sf)
{
int   s, m, h;
static char str[40];

   s = (int) sf;
   m = s/60;
   s = s % 60;
   h = m/60;
   m = m % 60;
   sprintf(str, "%dh %dm %ds",h,m,s);
   return str;
} 
void pr_end_timer(char *msg, clock_t real, struct tms * tmsstart, struct tms *tmssend)
{
  float r, u, s;
  static long clktck=0;

  clktck=sysconf(_SC_CLK_TCK);
  r = real/(double) clktck;
  u = (tmssend->tms_utime - tmsstart->tms_utime)/(double) clktck;
  s = (tmssend->tms_stime - tmsstart->tms_stime)/(double) clktck;
  
  if (r>60.0) { 
     sprintf(ZBuf, "%s  Real time %-12s ", msg, timer_str(r)); Outlog;
     sprintf(ZBuf, "User time %-12s ", timer_str(u)); Outlog;
     sprintf(ZBuf, "Sys time %-12s\n", timer_str(s)); Outlog;
  }
  else {
     sprintf(ZBuf,"%s Real time %5.3fs   User time %5.3fs   Sys time %5.3fs\n", 
            msg, r, u, s); Outlog;
  }
  ZBuf[0] = '\0';
}
/**************************************************************
       Zscore_grand
to determine what clones have best matches and hence, start with in cb_compute
**************************************************************/
void Zscore_grand(int i, int exponent)
{
     ZZ.matrix[i].grand += (exponent * exponent);
}

/**************************************************************
                 Zscore_grand2 - add on len
**********************************************************************/
void Zscore_grand2(int i)
{
     if (ZZ.matrix[i].grand == 0) {
        ZZ.matrix[i].cbmap = ZIGNORED;
     }
     else if (ZZ.matrix[i].mtype & IAM_CHILD)
        ZZ.matrix[i].grand = 1;
     else 
        ZZ.matrix[i].grand += (3 * ZZ.matrix[i].nbands);
     ZZ.matrix[i].save_grand = ZZ.matrix[i].grand;
}
/**********************************************************************
                           DEF: init_Zclone
**********************************************************************/
void init_Zclone(int c)
{
int i;

    /* do not set ZZ.matrix[c].cbmap */
    /* or ZZ.matrix[c].max_extra is dimension of extra array */
    for (i=0; i<ZZ.matrix[c].n_extra; i++)
        ZZ.matrix[c].extra[i] = -1;
    ZZ.matrix[c].n_extra= 0;  
    ZZ.matrix[c].rightb = ZZ.matrix[c].leftb = 0;
    ZZ.matrix[c].pick = -1;
    ZZ.matrix[c].n_cb = 0;
    ZZ.matrix[c].cbQ= 0;
    if (ZZ.matrix[c].cb_index!=NULL) ZZ.matrix[c].cb_index[0] = BIG_NEG_NUM;
    ZZ.matrix[c].mtype = ZZ.matrix[c].save_mtype;
    ZZ.matrix[c].high_match = ZZ.matrix[c].save_high_match;
}
/********************************************************************/
void free_Zclone(int c)
{
    if (ZZ.matrix[c].n_extra>0) ZFREE(ZZ.matrix[c].extra, "extra");
    if (ZZ.matrix[c].cb_index != NULL) ZFREE(ZZ.matrix[c].cb_index, "cb_index");
}
/*******************************************************
                    DEF: init_Zset
********************************************************/
void init_Zset(int z, int ntries)
{
int j;

     if (!ntries) { /* if ntries is 0, then this is the first initialization */
        Zset[z].score = Zset[z].avg = 0.0;
        Zset[z].low = 9999;
        Zset[z].n_Qs = 0;
        Zset[z].ctg = 0;
                    /* these are set in assign_clones_to_cbmap */
        Zset[z].n_clone = 0;
        Zset[z].csort = NULL;
     }
                    /* these are used by cb_assemble - reset for each Ntries */
     if (Zset[z].n_clone > 0) { 
        for (j=0; j< Zset[z].n_band; j++) {
            if (Zset[z].root[j].clone!=NULL) free(Zset[z].root[j].clone);
            if (Zset[z].root[j].val!=NULL) free(Zset[z].root[j].val);
        }
        if (Zset[z].root!=NULL) free(Zset[z].root);
        if (Zset[z].group!=NULL) free(Zset[z].group);
     }
     Zset[z].root = NULL;
     Zset[z].band = NULL;
     Zset[z].group = NULL;
     Zset[z].n_added_clone =  0;
     Zset[z].n_band = Zset[z].max_band = 0;
     Zset[z].n_group = Zset[z].max_group = 0;
     Zset[z].leftb = 0;
     Zset[z].rightb = -1;
     Zset[z].far_leftb = 0;
     Zset[z].far_rightb = 0;
     
     for (j=0; j < HANG; j++) 
        Zset[z].hang_left[j] = Zset[z].hang_right[j] = -1; 
     for (j=0; j<max_Zpq; j++) { 
       Zpq[j].C =  Zpq[j].score = Zpq[j].parent = -1;
       Zpq[j].fstbg = Zpq[j].lastbg = 0;
     }
     n_Zpq=0;
     Zpick=0;
}
/*******************************************************
                    DEF: get_Zset
********************************************************/
int get_Zset()
{
int S, i;

   if (n_Zset == max_Zset) {
       if (max_Zset==0) Zset = NULL;
       max_Zset += 5;
       if (Zset==NULL) Zset = (ZSETZ *) calloc(max_Zset, sizeof(ZSETZ));
       else Zset = (ZSETZ *) realloc(Zset, sizeof(ZSETZ) * max_Zset);
       NOMEM3a(Zset, "Zset", -1, max_Zset,sizeof(ZSETZ) * max_Zset);
       for (i=n_Zset; i < max_Zset; i++) init_Zset(i,0);
   }
   S = n_Zset;
   n_Zset++;
   Zpick=0;
return S;
}

/****************************************************************
                       Def: Zbuild_matrix
****************************************************************/
int Zbuild_matrix(int ctg)
{
char ctgname[12];
int c, cnt, i, j;
CLONE *clp;

  if (!arrayExists(bands)) 
      if (fpRead() == -1) {
          fprintf(stderr,"ERROR: cannot read band file\n");
          return 0;
      }
  total_cmp= 0.0;
  cnt_overlap= cnt_nodes=0;
  if (ctg ==0) { /* Build contigs */
     scanClam2(); 
     init_CpM(1); Outlog;
     cnt = contigs[0].count;
  }
  else {         /* called from Contig Analysis */
     scanClamA();
     init_CpM(0);
     if (merging) cnt = 
         contigs[mergecontig1].count+contigs[mergecontig2].count;
     else cnt = contigs[ctg].count;
  }

  sprintf(ctgname, "Ctg%d", ctg);
  if (Zcreate_instance(ctgname, &ZZ, cnt)==0) {
      fprintf(stderr,"FPC ERROR: cannot create instance in Build Matrix\n");
      return 0;
  }
  
  ZZ.ctg = ctg;
  ZZ.tol = Pz.tol; 
  ZZ.cut = Pz.cutFlt;
  ZZ.cutOK = Pz.cutFlt*100;

  for (i=0; i < ZZ.size; i++) {
       /* these fields stay static once set */
     ZZ.matrix[i].nbands = 0;
     ZZ.matrix[i].cin =  -1;
     ZZ.matrix[i].cbmap  = -1;
       /* grand only gets reset if Again is run from CB map */
     ZZ.matrix[i].grand = ZZ.matrix[i].save_grand=0;
       /* these fields are used in cb_assemble, and reset of each Do_Best */
     ZZ.matrix[i].mtype= ZZ.matrix[i].save_mtype = IAM_NOTHING;
     ZZ.matrix[i].high_match= ZZ.matrix[i].save_high_match = -1;
     ZZ.matrix[i].grand = 0;
     ZZ.matrix[i].leftb = ZZ.matrix[i].rightb = 0;
     ZZ.matrix[i].n_extra = ZZ.matrix[i].max_extra = 0;
     ZZ.matrix[i].cbQ= 0;
     ZZ.matrix[i].pick =  -1;
     ZZ.matrix[i].extra = NULL;
     ZZ.matrix[i].n_cb = 0;
  }
  if (ctg==0) goto BUILD_CONTIGS;

/* these two lines are here for so not done on second contig for merging */
  c = ctg; 
  j=0;
SINGLE_CTG: ; 
             /* use this instead root so same solution as from Build Contigs  */
   for (i= contigs[c].start; i != -1; i = clp->next)
   {
        clp = arrp(acedata, i, CLONE);
        if (clp->fp == NULL || clp->fp->b2==0) continue;  
        if (LastCB==Select && clp->selected==0) continue; /* cari 25mar05 */
         
        if (IsSeq(clp)) 
             ZZ.matrix[j].save_mtype = ZZ.matrix[j].mtype=IAM_MOM; /* can't be buried */

        /* Exact and Approx buried will stay that way. The assembly routine
           keeps them near their parents. Pseudos are not kept near parents
           as they are pretty lose buries */
        if (clp->mattype == PARENT || clp->mattype == PSPARENT) 
             ZZ.matrix[j].save_mtype = ZZ.matrix[j].mtype=IAM_MOM;
        else if (clp->mattype != PSEUDO && clp->match[0] != ' ') 
             ZZ.matrix[j].save_mtype = ZZ.matrix[j].mtype = 
               (clp->mattype==EXACT) ? IAM_EXACT:IAM_APPROX;
        ZZ.matrix[j].cin =  i;
        ZZ.matrix[j].nbands = clp->fp->b2;
        
        clp->matrix_location = j; /* for parallel */
        
        j++;
    }
    if (merging && c != mergecontig2) {
        c = mergecontig2;
        goto SINGLE_CTG;
    }
    ZZ.size = j;
    goto DONE;
 
BUILD_CONTIGS: ;
     for (j=0, i= contigs[0].start; i != -1; i = clp->next)
     {
        clp = arrp(acedata, i, CLONE);
        if (SIM_FLAG) 
              clear_old_remarks(clp);
        if (clp->clone[0]=='!' || clp->fp == NULL || clp->fp->b2<Pz.minBands) continue; /*CAS 5.6*/
        if (IsSeq(clp)) ZZ.matrix[j].save_mtype = ZZ.matrix[j].mtype=IAM_MOM;
        ZZ.matrix[j].cin =  i;
        ZZ.matrix[j].nbands = clp->fp->b2;
        j++;
     }
     ZZ.size = j;
     sprintf(ZBuf,"Clones to process: %d \n", ZZ.size); Outlog;
  
DONE: ;
  total_cmp = ((float)j * ((float) (j-1))) / 2.0;
  if (!Zadd && !Zorder && LastCB!=Select) 
  {
    if (LastCB == Calc)
       fprintf(stdout, 
          "Begin: Ctg%d  %.0f comparisons (Cutoff %0.e Tol %d  Best of %d) \n",
             ctg,  total_cmp, Pz.cutFlt, Pz.tol, Pz.bestInt);
    else {
         fprintf(stdout,
   "Begin: Ctg%d %.0f comparisons (Eq %d Gellen %d Cutoff %0.e Tol %d  Best of %d)\n",
             ctg, total_cmp, Proj.eq2,  Proj.gel_len, Pz.cutFlt, Pz.tol, Pz.bestInt);
    }
  }
  total_cmp=0.0;
return j;
}

/***************************************************************
                       Def: Zcreate_node
****************************************************************/
int Zcreate_node(int i)
{
int  j, n;
ZNODE *node, *node2;
int exponent;
CLONE *clonei, *clonej;
int i1,i2;
int ZscoreCpM(struct tmpCz*, struct tmpCz*, struct tmpSz*);

    /* could happen in Calc, if user put zero band clone in contig  */
     if (!loadCz(&C1z, ZZ.matrix[i].cin )) {
          ZZ.matrix[i].cbmap  = ZNOT_USED;
          return 1;
     }
     clonei = arrp(acedata, ZZ.matrix[i].cin, CLONE);

     cnt_nodes++;

     ZZ.matrix[i].cb_index = (int *) malloc((C1z.nbands+1)*sizeof(int));
     NOMEM3(ZZ.matrix[i].cb_index, "cb_index", 1);
     ZZ.matrix[i].cb_index[0] = BIG_NEG_NUM;

     if (Zadd || Zorder) n= 0; else n = i+1;
     for (j = n; j < ZZ.size;  j++)
     {
         if (j==i) continue;
         if (ZZ.matrix[j].cbmap==ZNOT_USED) continue;

         clonej = arrp(acedata, ZZ.matrix[j].cin, CLONE);
         if (LastCB==Select && clonej->selected==0) continue;

         if (!loadCz(&C2z, ZZ.matrix[j].cin)) continue;

         Zsulston(&C1z,&C2z,&Sz);
         exponent = ZscoreCpM(&C1z,&C2z,&Sz);

            /* high_match is set for new buried in Find_possible_buried, 
               but not known for existing buried until here */
         if (strcmp(clonei->match, clonej->clone)==0) {
                            /* may be bad, so don't try to keep w/parent*/ 
             if (clonei->mattype!=PSEUDO) 
                  ZZ.matrix[i].save_high_match = ZZ.matrix[i].high_match = j;
             if (exponent==0) exponent=1; /* may be a bad user bury */
         }
         if (strcmp(clonej->match, clonei->clone)==0) {
             if (clonej->mattype!=PSEUDO)  
                  ZZ.matrix[j].save_high_match = ZZ.matrix[j].high_match = i;
             if (exponent==0) exponent=1; 
         }
         cnt_cmp++;
         total_cmp += 1.0;
    
         if (SIM_FLAG)
         {
             compute_f_plus_f_minus(exponent,clonei,clonej,ZZ.matrix[i].cin,ZZ.matrix[j].cin);
         }
    
         if (exponent == 0) continue;

         cnt_overlap++;

         Zscore_grand(i, exponent);
         node = Znew_node_serial(i, j);
         node->match = Sz.match;
         node->exponent = exponent;

         Zscore_grand(j, exponent);
         node2 = Znew_node_serial(j, i);
         node2->match = Sz.match;
         node2->exponent = exponent;
     }
     if (cnt_cmp >= 100000 && !Zbatch_flag) {
      fprintf(stdout," at clone #%d, compared %.0f, overlaps %d, average %6.3f: %02.2f%% done\r",
           i, (float) total_cmp, cnt_overlap, (float)cnt_overlap/(float) cnt_nodes,
      ((float)total_cmp * 100.0 )/
                 (((double)ZZ.size * ((double)ZZ.size + 1.0) )* 0.5)); 
         fflush(stdout);
         cnt_cmp=0;
         if (!Zbatch_flag && graphInterruptCalled()) {
              printf("F4 pre-mature termination of %s\n", Fn);
              return 0;
         }
     }
     Zscore_grand2(i); /* adds length to entry i */
return 1;
}
/***************************************************************
                       Def: Zcreate_node_shared
this is called from shared_node_creation in share.c
****************************************************************/
int Zcreate_node_shared(int i, int procID)
{
   int  j;
   ZNODE *node = NULL;
   int exponent;
   CLONE clonei, clonej;
   
   struct tmpCz clone1z, clone2z;
   struct tmpSz result;
   
   loadCzfast(&clone1z, ZZ.matrix[i].cin);
   
   result.match = result.olap = 0;
   result.prob = 0;
   
   ZZ.matrix[i].cb_index = (int *) malloc((clone1z.nbands+1)*sizeof(int));
   NOMEM3(ZZ.matrix[i].cb_index, "cb_index", 1);
   ZZ.matrix[i].cb_index[0] = BIG_NEG_NUM;
   ZZ.matrix[i].grand = 0;

   clonei = arr(acedata, ZZ.matrix[i].cin, CLONE);

   local_cnt_nodes[procID]++;
   
   for (j=i+1; j < ZZ.size;  j++)
   {
      if (j==i) continue;
         
      clonej = arr(acedata, ZZ.matrix[j].cin, CLONE);
      if (ZZ.matrix[j].cbmap == ZNOT_USED) continue;
       
      if (!loadCzfast(&clone2z, ZZ.matrix[j].cin)) {
         ZZ.matrix[j].cbmap  = ZNOT_USED;
         continue;
      }   
            
      Zsulston(&clone1z, &clone2z, &result);
      exponent = ZscoreCpM(&clone1z, &clone2z, &result);
      
      if (strcmp(clonei.match, clonej.clone)==0) {
                            /* may be bad, so don't try to keep w/parent*/ 
          if (clonei.mattype!=PSEUDO) 
               ZZ.matrix[i].save_high_match = ZZ.matrix[i].high_match = j;
          if (exponent==0) exponent=1; /* may be a bad user bury */
      }
      if (strcmp(clonej.match, clonei.clone)==0) {
          if (clonej.mattype!=PSEUDO)  
              ZZ.matrix[j].save_high_match = ZZ.matrix[j].high_match = i;
          if (exponent==0) exponent=1; 
      }
      
      local_cnt_cmp[procID]++;
      if(local_cnt_cmp[procID] >= 100000) {
         sem_wait(&cmp_mutex);
         total_cmp += local_cnt_cmp[procID];
         printf("%.0f comparisons processed: %02.2f%% done\r", 
           (float) total_cmp,((float)total_cmp * 100.0 )/
                 (((double)ZZ.size * ((double)ZZ.size + 1.0) )* 0.5)); 
        fflush(stdout);   
        sem_post(&cmp_mutex);     
        local_cnt_cmp[procID] = 0;
      }
      
      if (SIM_FLAG) {
            compute_f_plus_f_minus(exponent,&clonei,&clonej,ZZ.matrix[i].cin,ZZ.matrix[j].cin);
      }
       
      if (exponent == 0) continue;
      
      local_cnt_olap[procID]++;
 
      Zscore_grand(i, exponent);
      node = (ZNODE *) Znew_node_shared(i, j, procID);
      node->match = result.match;
      node->exponent = exponent;
   }   
   // Zscore_grand2(i); need to do this after fill in lower diagonal 
   return 1;
}

/*************************************************************/
static struct tmpBz {
   int   cin, z, grand, nbands;
} *tmz;

static int sortBz(const void *orig_a, const void *orig_b)
{
  struct tmpBz *a;
  struct tmpBz *b;

  a = (struct tmpBz *)orig_a;
  b = (struct tmpBz *)orig_b;

   if (a->nbands < b->nbands) return 1;
   if (a->nbands > b->nbands) return -1;
   if (a->grand < b->grand) return 1;
   if (a->grand > b->grand) return -1;
   return strcmp(arr(acedata,a->cin, CLONE).clone, 
                 arr(acedata,b->cin, CLONE).clone);
}
/**************************************************************
             DEF: Zmark_possible_buried
***************************************************************/
void Zmark_possible_buried()
{
ZNODE *node;
int i, z;

  tmz = (struct tmpBz *) malloc(ZZ.size * sizeof(struct tmpBz));
  NOMEM2(tmz, "tmz");

  for (i=0; i< ZZ.size; i++)
  {
     tmz[i].z = i;
     tmz[i].grand = ZZ.matrix[i].grand;
     tmz[i].cin = ZZ.matrix[i].cin;
     tmz[i].nbands = ZZ.matrix[i].nbands;
  }
  qsort(tmz, ZZ.size, sizeof(struct tmpBz), sortBz);

  for (z=0; z<ZZ.size; z++) {
     if (ZZ.matrix[tmz[z].z].mtype & IAM_CHILD ) continue;

     while ((node = Ztraverse(tmz[z].z))) {
         i = node->i2;
         if (ZZ.matrix[i].mtype != IAM_NOTHING) continue;

         if (ZZ.matrix[i].nbands == node->match) 
         {
             ZZ.matrix[i].save_high_match = ZZ.matrix[i].high_match = tmz[z].z;  
             ZZ.matrix[i].save_mtype = ZZ.matrix[i].mtype = IAM_EXACT;  
             ZZ.matrix[i].grand = ZZ.matrix[i].save_grand = 1;  
             ZZ.matrix[tmz[z].z].save_mtype = ZZ.matrix[tmz[z].z].mtype = IAM_MOM;  
         }
     }
  }
  for (z=0; z<ZZ.size; z++) {
     if (ZZ.matrix[tmz[z].z].mtype & IAM_CHILD ) continue;

     while ((node = Ztraverse(tmz[z].z))) {
         i = node->i2;
         if (ZZ.matrix[i].mtype != IAM_NOTHING) continue;
         Sz.match = node->match;

         if (IsBuried(ZZ.matrix[i].nbands))
         {
             ZZ.matrix[i].save_high_match = ZZ.matrix[i].high_match = tmz[z].z;  
             ZZ.matrix[i].save_mtype = ZZ.matrix[i].mtype = IAM_APPROX;  
             ZZ.matrix[i].grand = ZZ.matrix[i].save_grand = 1;  
             ZZ.matrix[tmz[z].z].save_mtype = ZZ.matrix[tmz[z].z].mtype = IAM_MOM;  
         }
     }
  }
  free(tmz);
}
/**************************************************************
             DEF: Zfree all structures for building cb
called in cleanCB, for after its been display in the CBmap viewer
and by Build Contigs, IBC, DQer, and Reanalyze
***************************************************************/
void Zfree_cb_data_structures()
{
int b, i;

    for (b=0; b< n_Zset; b++)
    {
         for (i=0; i<Zset[b].n_band; i++)
             if (Zset[b].root[i].max > 0) { 
                 if (Zset[b].root[i].clone!=NULL) free(Zset[b].root[i].clone);
                 if (Zset[b].root[i].val!=NULL) free(Zset[b].root[i].val);
             }
         if (Zset[b].root!=NULL) free(Zset[b].root);
         if (Zset[b].group!=NULL) free(Zset[b].group);
         if (Zset[b].csort!=NULL) free(Zset[b].csort); 
    }
    if (Zset!=NULL) free(Zset);
    if (Zpq!=NULL) free(Zpq);

    for (i=0; i<ZZ.size; i++) {
        if (ZZ.matrix[i].extra!=NULL) free(ZZ.matrix[i].extra);
        if (ZZ.matrix[i].cb_index != NULL) free(ZZ.matrix[i].cb_index);
    }
    Zdestroy_instance(&ZZ);

    Zadd=0;
    Zpq = NULL;
    Zset = NULL;
    n_Zpq = n_Zset = max_Zpq = max_Zset = 0;
    ZS = -1;
    cnt_nodes=0;
    LastCB=NoCB;
}
/**********************************************************************
                           DEF: little_wrap_up
**********************************************************************/
void little_wrap_up()
{
   if (ZS== -1 || n_Zset==0) {
       n_Zset=0;
       sprintf(ZBuf, "No CBmap!!!!"); showClam(); showClam2();
       sprintf(ZBuf, "No CBmaps!!!!\n"); Outlog;
       quitCB();
       return;
   }
   sprintf(ZBuf,
         "  %s Ctg%-4d CBmap %-4d Clones %-4d CBs %-5d  Qs %-3d Score %4.3f\n",
          Fn, currentctg, ZS+1, Zset[ZS].n_clone, Zset[ZS].n_band, Zset[ZS].n_Qs,
          ((Zset[ZS].score*1000.0)/1000.0)); Outlog;

   drawCBmap();
   if(graphActivate(g99))
      graphPop();
}

/**********************************************************************
                           DEF: big_wrap_up
flag 0 - build, flag 1 - calc
**********************************************************************/
void big_wrap_up(int flag)
{
int i;
void  print_CpMcnts(); 
int cnt_Q_ctg=0, num_Q=0, over_Q=0, under_Q=0;
float avg_high_score=0.0, olap;
void print_CpMcnts();

   if (ZS== -1 || n_Zset==0) {
       n_Zset=0;
       sprintf(ZBuf, "No CBmaps!!!!"); showClam(); showClam2();
       sprintf(ZBuf, "No CBmaps!!!!\n"); Outlog;
       ZBuf[0]='\0';
       quitCB();
       return;
   }

   for (Ignored_clones=i=0; i<ZZ.size; i++) 
       if ((ZZ.matrix[i].cbmap == ZSET || ZZ.matrix[i].cbmap==ZIGNORED)) 
                 Ignored_clones++; 

   for (i=0; i<n_Zset; i++) {
        num_Q += Zset[i].n_Qs;
        if (Zset[i].n_Qs>0) cnt_Q_ctg++;
        if (Zset[i].n_Qs>Pz.DQnumq) over_Q++;
        if (Zset[i].n_Qs<=Pz.DQnumq && Zset[i].n_Qs>0) under_Q++;
        avg_high_score += Zset[i].score;
   }
   olap = (float)cnt_overlap/cnt_nodes;
   avg_high_score /= (float) n_Zset;

   sprintf(ZBuf,"Singles %d Ctgs %d Qs %d", Ignored_clones, n_Zset, num_Q); 
   if (flag==0) {
     if (!Zbatch_flag) {
         Zproj_results(2);
         showClam2();
     }
     sprintf(ZBuf,"\nComplete Build: Tol %d Cut %.0e%s Bury~ %3.2f Best %d\n",
         Pz.tol,  Pz.cutFlt,CpMtype[Cp.useFlag],  Pz.burFlt, Pz.bestInt); Outlog;
     print_CpMcnts(); Outlog;
   }
   else {
     if(!qstuff ){ /* cari 11feb05 */
        showClam(); 
        fflush(stdout);
        ZS=0;
        drawCBmap();
        if(graphActivate(g99)) graphPop();
     }
   }
   if (n_Zset > 1) {
     sprintf(ZBuf,
     "Singles %d AvgOverlap %-4.1f AvgScore %-4.3f Qs %d(%d) (<=%dQs %d  >%dQs %d)\n",
       Ignored_clones, olap, avg_high_score, num_Q, cnt_Q_ctg, 
       Pz.DQnumq, under_Q, Pz.DQnumq, over_Q); Outlog;
   }
   ZBuf[0] = '\0';
}


/* This function computes the number of F+ and F- clones */

static void compute_f_plus_f_minus (int exponent,CLONE *clonei, CLONE *clonej,int i, int j)
{
   int clonei_lc,clonei_rc,clonej_lc,clonej_rc;
   char remark[COMMENT_SZ+1];  /* comment is 41 */
   int sim_is_adjacent();

   if (CLONE_SZ+7 > COMMENT_SZ) {
      fprintf(stderr,"CLONE SIZE is too large for comment\n");
      exit(0);
   }
   if(clonei->fp_remark == NULL || clonej->fp_remark == NULL)
   {
      return ;
   }

   compute_coords(&clonei_lc, &clonei_rc, clonei);
   compute_coords(&clonej_lc, &clonej_rc, clonej);
   //Check if the coordinates intersect and appropriately
   // calculate F+ and F-
   if(coord_intersect(clonei_lc,clonei_rc,clonej_lc,clonej_rc))
   {
      if (exponent == 0 && sim_is_adjacent(clonei,clonej))
      {
         if (SHARED_OPTION) 
             sem_wait(&false_neg_mutex);
         false_neg ++;

         sprintf(remark,"FMinus %s", clonej->clone);
         append_remark(i,remark);

         sprintf(remark,"FMinus %s", clonei->clone);
         append_remark(j,remark);

         if (SHARED_OPTION) 
             sem_post(&false_neg_mutex);
      }
   }
   else
   {
      if (SHARED_OPTION) 
         sem_wait(&false_pos_mutex);
      
      if (exponent != 0)
      {
         false_pos ++;

         sprintf(remark,"FPlus %s", clonej->clone);
         append_remark(i,remark);

         sprintf(remark,"FPlus %s", clonei->clone);
         append_remark(j,remark);
      }
      //The RC coordinates don't intersect and they are adj clones
      //Add to gaps

      if (sim_is_adjacent(clonei,clonej))
      {
         sprintf(remark,"Gap %s", clonej->clone);
         append_remark(i,remark);

         sprintf(remark,"Gap %s", clonei->clone);
         append_remark(j,remark);
         num_gaps ++;
      }

       if (SHARED_OPTION) 
         sem_post(&false_pos_mutex);
   }
}

//Gets the coordinates out of the clone name
static void compute_coords(int *lc,int *rc,  CLONE *clone)
{
   char string[2000];
   int i=1,j=0;
   if (clone->fp_remark == NULL)
   {
         printf("No fp_remark, hence, no coordinates.");
         printf("Abort simulation test.");
         exit(1);
   }

   //The remarks will be of the format (1234 3456)
   // It will always be the first fp_remark
   while((clone->fp_remark->message)[i] != ' ')   
   {
      string[j++] = (clone->fp_remark->message)[i];
      i++;
   }
   string[j] = '\0';
   *lc = atoi(string);

   while((clone->fp_remark->message)[i] == ' ')   
      i++;
      
   j = 0;

   while(clone->fp_remark->message[i] != ')')   
   {
      string[j++] = (clone->fp_remark->message)[i];
      i++;
   }
   string[j] = '\0';
   *rc = atoi(string);
}

//Checks if the coordinates of the 2 clones intersect
static int coord_intersect(int x1,int x2,int w1,int w2)
{
   if( x2 >= w1 && x1 <= w1)
   {
        return (1);
   }
   if (w2 >= x1 && w1 <= x1)
   {
        return (1);
   }
   return (0);
}

//This function clears the previous FMinus and FPlus remarks, and GAP
static void clear_old_remarks(CLONE *clone)
{   
struct remark *tmp;
struct remark *prev = NULL;

   for(tmp=clone->fp_remark; tmp != NULL; tmp=tmp->next)
   {
      if (strncmp(tmp->message,"FMinus",5)==0 || strncmp(tmp->message,"FPlus",5)==0
            || strncmp(tmp->message,"Gap",3)==0)
      {
          if(tmp->next == NULL){ /* last */
             if (prev == NULL) clone->fp_remark = NULL;
             else prev->next = NULL;
          }
          else if (prev == NULL) { /* first */
              clone->fp_remark = tmp->next;
          }
          else{
              prev->next = tmp->next;
          }
       }
       else prev = tmp;
   }
}

//Extracts the number from the clone name and checks if they are adjacent.

int sim_is_adjacent(CLONE *clonei, CLONE *clonej)
{
   char num[1000];
   int  num_i,num_j;

   int i=0, j = 0;
   //Clone names are of the following format
   //hu16_1234

   //Extract the first clone number

   while (clonei->clone[i] != '_')
   {
      i++;
   }
   i++;

   while(clonei->clone[i]!= '\0')
   {
      num[j++] = (clonei->clone)[i];
      i++;
   }
   num[j] = '\0';
   num_i = atoi(num);

   //Extract the second clone number
   i = j = 0;
   while (clonej->clone[i] != '_')
   {
      i++;
   }
   i++;

   while(clonej->clone[i]!= '\0')
   {
      num[j++] = clonej->clone[i];
      i++;
   }
   num[j] = '\0';
   num_j = atoi(num);


   //check if they are adjacent
   if (abs(num_j-num_i)==1) return 1;
   return 0;   
}
